/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.inspur.edp.lcm.metadata.servermanager.monitor;

import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackage;
import com.inspur.edp.lcm.metadata.cache.MetadataCacheManager;
import com.inspur.edp.lcm.metadata.cache.MetadataDistCacheManager;
import com.inspur.edp.lcm.metadata.cache.MetadataRtDistCache;
import com.inspur.edp.lcm.metadata.cache.RtCacheHandler;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.servermanager.event.MdPkgChangedEventBroker;
import com.inspur.edp.lcm.metadata.servermanager.persistent.RepositoryFactory;
import com.inspur.edp.lcm.metadata.spi.event.MdPkgChangedArgs;
import io.iec.edp.caf.commons.layeringcache.cache.Cache;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.i18n.framework.api.language.EcpLanguage;
import io.iec.edp.caf.i18n.framework.api.language.ILanguageService;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;

public class MdpkgListenerAdapter extends FileAlterationListenerAdaptor {

    public MdpkgListenerAdapter() {

    }
//    @Override
//    public void onStart(FileAlterationObserver observer) {
//        super.onStart(observer);
//    }
//
//    @Override
//    public void onStop(FileAlterationObserver observer) {
//        super.onStop(observer);
//    }

    @Override
    public void onFileCreate(File file) {
        try {
            super.onFileCreate(file);
            updateMdpkgAndMetadataCache(file, true);

        } catch (Exception e) {
            //todo
        }
    }

    @Override
    public void onFileDelete(File file) {
        try {
            //更新缓存信息，文件删除时，具体缓存应该移除
            super.onFileDelete(file);
            deleteMdpkgAndMetadataCache(file);
        } catch (Exception e) {
            //todo
        }
    }

    @Override
    public void onFileChange(File file) {
        try {
            //更新缓存信息
            super.onFileChange(file);
            updateMdpkgAndMetadataCache(file, false);
        } catch (Exception e) {
            //todo
        }

    }

    private void updateMdpkgAndMetadataCache(File file, boolean isAdd) {
        //更新缓存信息：包的信息会更新，因为所有后续获取内容，都依赖于已知的包的信息；所有的元数据内容不需要更新，仅需要移除。
        //当获取元数据时，如果缓存中没有元数据信息，会重新根据已知的包信息，重新加载元数据。
        //在更新元数据包缓存前，需要根据原有包的缓存信息，清理已有的元数据信息。
        //更新所有元数据信息列表
        //清理元数据信息、清理元数据引用信息
        //更新元数据包的信息：元数据包位置信息、元数据包中元数据列表信息、元数据包引用信息
        //更新元数据所在元数据包信息
        try {
            Cache metadataCache = MetadataDistCacheManager.getMetadataCache();
            Cache metadataRtCache = MetadataRtDistCache.getMetadataCache();
            MetadataPackage metadataPackage = RepositoryFactory.getInstance().getMetadataPackageRepository().getMetadataPackage(file);
            MetadataCacheManager.removeAllMetadataPackageInfo(RtCacheHandler.ALL_PACKAGES_CACHE_KEY);
            //清理元数据内容缓存，将原有缓存的包中元数据列表从元数据内容缓存移除
            String metadataKey = "";
            List<GspMetadata> oldPackageMetadataList = (List<GspMetadata>) MetadataCacheManager.getMDManifestInfo(metadataPackage.getHeader().getName());
            List<GspMetadata> allMetadataList = (List<GspMetadata>) MetadataCacheManager.getAllMetadataInfo(RtCacheHandler.ALL_METADATA_INFO_CACHE_KEY);
            if (oldPackageMetadataList != null && oldPackageMetadataList.size() > 0) {
                for (GspMetadata item : oldPackageMetadataList) {
                    metadataKey = RtCacheHandler.getMetadataCacheKey(item.getHeader().getId(), "");
                    MetadataCacheManager.removeMetadataInfo(metadataKey);
                    MetadataCacheManager.removeMDDependence(metadataKey);
                    MetadataCacheManager.removeMetadataPathMapping(metadataKey);

                    List<String> languages = getLanguages();
                    for (String language : languages) {
                        String key = RtCacheHandler.getMetadataCacheKey(item.getHeader().getId(), language);
                        MetadataCacheManager.removeMetadataInfo(key);
                        metadataCache.evict(key);
                        metadataRtCache.evict(key);//把指定的缓存对象清除
                    }
                }
                //清理并更新所有元数据缓存
                allMetadataList.removeAll(oldPackageMetadataList);
            }
            allMetadataList.addAll(metadataPackage.getMetadataList());
            MetadataCacheManager.addAllMetadataInfo(RtCacheHandler.ALL_METADATA_INFO_CACHE_KEY, allMetadataList);
            //清理并更新包中<元数据标识，元数据所在位置信息缓存>,清理过程在旧包处理过程中
            String metadataPackagePath = Utils.handlePath(file.toString());
            for (GspMetadata item : metadataPackage.getMetadataList()) {
                metadataKey = RtCacheHandler.getMetadataCacheKey(item.getHeader().getId(), "");
                MetadataCacheManager.addMetadataPathMapping(metadataKey, metadataPackagePath + item.getRelativePath());
            }
            //更新包缓存
            RtCacheHandler.updateMetadataPackageCache(metadataPackage.getHeader().getName(), metadataPackage);

            MdPkgChangedEventBroker broker = SpringBeanUtils.getBean(MdPkgChangedEventBroker.class);
            MdPkgChangedArgs args = new MdPkgChangedArgs();
            args.setMetadataPackage(metadataPackage);

            if (isAdd) {
                broker.fireMdPkgAddedEvent(args);
            } else {
                broker.fireMdPkgChangedEvent(args);
            }
        } catch (IOException e) {
            throw new RuntimeException("update metadatapackage cache filed, package is " + file, e);
        }
    }

    private void deleteMdpkgAndMetadataCache(File file) {
        //这时不需要获取元数据包中的内容，仅需要根据元数据包文件名称，移除内容即可。
        String packageFileName = file.getName();
        String packageName = packageFileName.substring(0, packageFileName.lastIndexOf("."));
        //清理元数据内容缓存，将原有缓存的包中元数据列表从元数据内容缓存移除
        String metadataKey = "";
        Cache metadataCache = MetadataDistCacheManager.getMetadataCache();
        Cache metadataRtCache = MetadataRtDistCache.getMetadataCache();

        List<GspMetadata> oldPackageMetadataList = (List<GspMetadata>) MetadataCacheManager.getMDManifestInfo(packageName);
        List<GspMetadata> allMetadataList = (List<GspMetadata>) MetadataCacheManager.getAllMetadataInfo(RtCacheHandler.ALL_METADATA_INFO_CACHE_KEY);
        if (oldPackageMetadataList != null && oldPackageMetadataList.size() > 0) {
            for (GspMetadata item : oldPackageMetadataList) {
                metadataKey = RtCacheHandler.getMetadataCacheKey(item.getHeader().getId(), "");
                MetadataCacheManager.removeMetadataInfo(metadataKey);
                MetadataCacheManager.removeMDDependence(metadataKey);
                MetadataCacheManager.removeMetadataPathMapping(metadataKey);
                List<String> languages = getLanguages();
                for (String language : languages) {
                    String key = RtCacheHandler.getMetadataCacheKey(item.getHeader().getId(), language);
                    MetadataCacheManager.removeMetadataInfo(key);
                    metadataCache.evict(key);
                    metadataRtCache.evict(key);
                }
            }
            //清理并更新所有元数据缓存
            allMetadataList.removeAll(oldPackageMetadataList);
        }
        //更新包缓存
        MetadataCacheManager.removeMetadataPackageInfo(packageName);
        MetadataCacheManager.removeMDManifestInfo(packageName);
        MetadataCacheManager.removeMPDependence(packageName);
        MetadataCacheManager.removeAllMetadataPackageInfo(RtCacheHandler.ALL_PACKAGES_CACHE_KEY);
    }

    private static List<String> languages;

    private static List<String> getLanguages() {
        if (languages == null || languages.size() <= 0) {
            languages = new ArrayList<>();
            ILanguageService laguageService = SpringBeanUtils.getBean(ILanguageService.class);
            List<EcpLanguage> ecpLanguages = laguageService.getEnabledLanguages();
            for (EcpLanguage language : ecpLanguages) {
                languages.add(language.getCode());
            }
        }
        return languages;
    }
}
